/*
 * ReportTask.java
 *
 * Created on April 15, 2008, 10:27 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.sunspotworld;

import com.sun.spot.peripheral.ChannelBusyException;
import com.sun.spot.peripheral.NoAckException;
import com.sun.spot.peripheral.Spot;
import java.io.IOException;
import org.sunspotworld.sensortasks.SensorTask;
import com.sun.spot.peripheral.radio.IRadiogramProtocolManager;
import com.sun.spot.peripheral.radio.LowPan;
import com.sun.spot.peripheral.radio.RadioPacket;
import com.sun.spot.peripheral.radio.RadioPolicy;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Utils;
import java.util.Random;
import org.sunspotworld.datawrappers.DataWrapperVector;
import org.sunspotworld.hardware.LEDManager;
import org.sunspotworld.mydatawrappers.TrackingPacket;
import org.sunspotworld.mydatawrappers.TrackingPacketFactory;
import org.sunspotworld.protocols.MyProtocols;
import org.sunspotworld.sensortasks.TimeKeeper;

/**
 *
 * @author me
 */
public class ReportTask extends SensorTask {
    private static final int PAYLOAD_SIZE = RadioPacket.MIN_PAYLOAD_LENGTH - IRadiogramProtocolManager.DATA_OFFSET;
    private static final int RANDOM_BACKOFF = 10;
    private static final int CONSTANT_BACKOFF = 2;
    private static final int BROADCAST_RETRIES = 5;
    private long stop = 0;
    private static byte[] buffer = new byte[PAYLOAD_SIZE];
    private static int size = 1;
    private int retries = 0;
    private static IEEEAddress ourAddress = new IEEEAddress(System.getProperty("IEEE_ADDRESS"));
    private static byte numPkts = 0;
    
    private Random random = new Random(ourAddress.asLong());
    private IEEEAddress toAddress = new IEEEAddress(ourAddress.asDottedHex().substring(0,15) + "49F8");
    
    /** Creates a new instance of ReportTask */
    public ReportTask(long sample) {
        super.sampleInterval = sample;
    }
    
    private ReportTask(long sample, long id) {
        super.sampleInterval = sample;
        super.id = id;
    }
    
    protected SensorTask copy() {
        SensorTask task = (SensorTask)(new ReportTask(super.sampleInterval, super.id));
        task.setRepeat(super.repeating);
        return task;
    }

    public void runTask() {
        stop = TimeKeeper.getInstance().currentTimeMillis() + super.sampleInterval;
        //Spot.getInstance().getRadioPolicyManager().policyHasChanged(TimeKeeper.getInstance(), RadioPolicy.ON);
        System.out.println("reporting");
        TrackingPacket packet;
        synchronized (DataWrapperVector.getInstance()) {
            while (!DataWrapperVector.getInstance().isEmpty() && TimeKeeper.getInstance().currentTimeMillis() < stop) {
                while (!DataWrapperVector.getInstance().isEmpty() && size < PAYLOAD_SIZE - DataWrapperVector.getInstance().getMaxSize()) {
                    //LEDManager.getInstance().toggleLED(3);
                    packet = (TrackingPacket) DataWrapperVector.getInstance().dequeue();
                    System.out.println("Type: " + packet.getType());
                    System.out.println(TrackingPacketFactory.getInstance().printHeader(packet));
                    System.out.println(packet.printEntryLine());
                    //write to packet
                    packet.writeToBuffer(buffer, size);
                    
                    try {
                        System.out.println(TrackingPacketFactory.getInstance().constructDataWrapper(buffer, size).printEntryLine());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                        
                    size += packet.getSize();
                    numPkts++;
                }
                System.out.println("size: " + size);
                //send packet
                buffer[0] = numPkts;
                sendPacket();
            }
        }
        //Spot.getInstance().getRadioPolicyManager().policyHasChanged(TimeKeeper.getInstance(), RadioPolicy.OFF);
    }
    
    private void sendPacket () {
        System.out.println("Sending to: " + toAddress.asDottedHex());
        try {
            LowPan.getInstance().sendWithoutMeshingOrFragmentation(MyProtocols.DATA_TRANSFER, toAddress.asLong(), buffer, 0, size);
            System.out.println("sent");
            size = 1;
            numPkts = 0;
        } catch (NoAckException ex) {
            if (retries < BROADCAST_RETRIES && TimeKeeper.getInstance().currentTimeMillis() < stop) {  //if retried less than 5 times and there's enough time left
                retries++;
                sendPacket();
            } else {
                ex.printStackTrace();
            }
        } catch (ChannelBusyException ex) {
            if (TimeKeeper.getInstance().currentTimeMillis() + RANDOM_BACKOFF + CONSTANT_BACKOFF< stop) {  //if there's enough time left
                //retry if channel busy
                Utils.sleep(random.nextInt(RANDOM_BACKOFF) + CONSTANT_BACKOFF);  // wait a random amount before retrying
                sendPacket();
            }
        }
        retries = 0;  //retries resets after first recursive call of sendPacket falls through to here
    }
}
